﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using TrinityCreator.Helpers;

namespace TrinityCreator.UI.UIElements
{
    public class BitmaskStackPanel : StackPanel
    {
        public BitmaskStackPanel(string name, List<BitmaskCheckBox> checkboxes, long defaultValue = 0)
        {
            Name = name;
            Checkboxes = checkboxes;
            DefaultValue = defaultValue;

            foreach (var bmcb in Checkboxes)
            {
                Children.Add(bmcb);
                bmcb.Checked += RaiseBmspChanged;
                bmcb.Unchecked += RaiseBmspChanged;
            }
        }

        List<BitmaskCheckBox> checkboxes;

        public List<BitmaskCheckBox> Checkboxes {
            get { return checkboxes; }
            set { checkboxes = value; }
        }

        public string SelectionText
        {
            get { return ToString(); }
        }

        public long BitmaskValue
        {
            get
            {
                long bitmask = 0;
                var checkedCount = 0;
                foreach (CheckBox cb in Checkboxes)
                {
                    if (cb.IsChecked == true)
                    {
                        bitmask += (long) cb.Tag;
                        checkedCount++;
                    }
                }
                if (checkedCount == 0 && bitmask != DefaultValue)
                    bitmask = DefaultValue;
                return bitmask;
            }
            set { SetBitmaskValue(value); }
        }

        public long DefaultValue { get; set; }

        private void RaiseBmspChanged(object sender, RoutedEventArgs e)
        {
            BmspChanged(sender, e);
        }

        public event EventHandler BmspChanged = delegate { };

        /// <summary>
        /// 
        /// </summary>
        /// <param name="bmv"></param>
        private void SetBitmaskValue(long bmv)
        {
            var bitValues = new List<long>();
            bitValues.Add(0);
            bitValues.Add(1);
            for (long i = 0; i < 31; i++)
            {
                bitValues.Add(bitValues.Last()*2);
                Console.WriteLine(bitValues.Last());
            }
            bitValues.Reverse();

            foreach (var bitmask in bitValues)
                if (bmv >= bitmask)
                    foreach (var cb in Checkboxes)
                        if ((long) cb.Tag >= bitmask)
                        {
                            cb.IsChecked = true;
                            bmv -= bitmask;
                            break;
                        }
        }

        /// <summary>
        /// Sets IsChecked for one specific flag
        /// </summary>
        public void SetValueIsChecked(long key, bool isChecked)
        {
            foreach (CheckBox c in checkboxes)
            {
                long cbKey = (long)c.Tag;
                if (cbKey == key)
                {
                    c.IsChecked = isChecked;
                    break;
                }
            }
        }

        /// <summary>
        ///     Gets clean comma seperated text from checked BitmaskCheckboxes
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            var list = new List<string>();
            foreach (BitmaskCheckBox c in Children)
                if (c.IsChecked == true)
                    list.Add(c.Content.ToString());
            return string.Join(", ", list);
        }

        public static BitmaskStackPanel GetItemFlags()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "灵魂绑定"),
                new BitmaskCheckBox(2, "魔法制造的物品"),
                new BitmaskCheckBox(4, "可打开"),
                new BitmaskCheckBox(8, "上边有绿色的\"英雄\"文字"),
                new BitmaskCheckBox(16, "废弃物品"),
                new BitmaskCheckBox(32, "除非用法术,否则不能被摧毁"),
                new BitmaskCheckBox(64, "右键可激活"),
                new BitmaskCheckBox(128, "装备时没有默认的30秒冷却"),
                new BitmaskCheckBox(256, "包装纸"),
                new BitmaskCheckBox(512, "包裹，可以盛放其他物品"),
                new BitmaskCheckBox(1024, "Gifts-礼物?"),
                new BitmaskCheckBox(2048, "队伍掉落:可以被所有人拾取"),
                new BitmaskCheckBox(4096, "物品可以被退还"),
                new BitmaskCheckBox(8192, "公会或竞技场登记表"),
                new BitmaskCheckBox(16384, "未知，只有可以读的物品使用"),
                new BitmaskCheckBox(32768, "未知"),
                new BitmaskCheckBox(65536, "未知"),
                new BitmaskCheckBox(131072, "未知"),
                new BitmaskCheckBox(262144, "物品可以被选矿"),
                new BitmaskCheckBox(524288, "装备唯一"),
                new BitmaskCheckBox(1048576, "未知"),
                new BitmaskCheckBox(2097152, "物品可以在竞技场使用"),
                new BitmaskCheckBox(4194304, "异常(游戏中的提示)"),
                new BitmaskCheckBox(8388608, "变形时可用"),
                new BitmaskCheckBox(16777216, "未知"),
                new BitmaskCheckBox(33554432, "职业配方,只有当你符合条件时才会掉落"),
                new BitmaskCheckBox(67108864, "无法在竞技场中使用"),
                new BitmaskCheckBox(134217728, "账号绑定(需要同时把flags设置为7)", visibility: Visibility.Collapsed),
                new BitmaskCheckBox(268435456, "在触发标志时使用法术"),
                new BitmaskCheckBox(536870912, "未知"),
                new BitmaskCheckBox(1073741824, "未知"),
                new BitmaskCheckBox(2147483648, "拾取绑定，可交易"),
                // auto updated on item quality change
            };

            return new BitmaskStackPanel("itemFlagsSp", cbs);
        }

        internal static BitmaskStackPanel GetQuestFlags()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "玩家死亡后失败"),
                new BitmaskCheckBox(2, "队伍中的玩家都可以得到确认接收任务的提示"),
                new BitmaskCheckBox(4, "区域触发器激活"),
                new BitmaskCheckBox(8, "任务可以分享给其他玩家", true),
                new BitmaskCheckBox(16, "未知"),
                new BitmaskCheckBox(32, "史诗"),
                new BitmaskCheckBox(64, "团队任务"),
                new BitmaskCheckBox(128, "TBC及以后添加"),
                new BitmaskCheckBox(256, "任务需要源物品(RequiredSourceItemId字段不为空)"),
                new BitmaskCheckBox(512, "隐藏奖励", tooltip:"任务奖励物品和金钱隐藏,完成任务时才给予奖励"),
                new BitmaskCheckBox(1024, "任务完成时自动奖励,不在客户端任务面板显示"),
                new BitmaskCheckBox(2048, "德莱尼和血精灵的新手村任务"),
                new BitmaskCheckBox(4096, "日常"),
                new BitmaskCheckBox(8192, "可重复接受的任务"),
                new BitmaskCheckBox(16384, "一般不可用的任务"),
                new BitmaskCheckBox(32768, "周常"),
                new BitmaskCheckBox(65536, "自动完成"),
                new BitmaskCheckBox(131072, "需要使用RequiredItemId 和SourceItemId"),
                new BitmaskCheckBox(262144, "用任务目标文字代替任务完成文字"),
                new BitmaskCheckBox(524288, "自动接受")
            };

            return new BitmaskStackPanel("questFlagsSp", cbs);
        }
        internal static BitmaskStackPanel GetQuestSpecialFlags()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "任务可重复"),
                new BitmaskCheckBox(2, "任务只能由一些特殊事件完成(比如areatrigger_involvedrelation表的entry字段,施放法术来完成任务,spell_scripts表中的command7等等)"),
                new BitmaskCheckBox(4, "自动接取任务"), // Bind to Flag 524288
                new BitmaskCheckBox(8, "只用于地下城查找器的任务"),
                new BitmaskCheckBox(16, "月常任务"),
                new BitmaskCheckBox(32 ,"任务需要RequiredOrNpcGo字段内容,但不要击杀(一般是对目标施法)"), // good luck
            };

            return new BitmaskStackPanel("questSpecialFlagsSp", cbs);
        }

        internal static BitmaskStackPanel GetItemFlagsExtra()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "仅限部落"),
                new BitmaskCheckBox(2, "仅限联盟"),
                new BitmaskCheckBox(4, "ExtendedCost商品"),
                new BitmaskCheckBox(256, "该物品不用roll点"),
                new BitmaskCheckBox(512, "取消ROLL点"),
                new BitmaskCheckBox(16384, "普通标价"),
                new BitmaskCheckBox(131072, "战网账号绑定", visibility: Visibility.Collapsed),
                // auto updated on item quality change
                new BitmaskCheckBox(2097152, "不能被幻化"),
                new BitmaskCheckBox(4194304, "不能幻化该物品"),
                new BitmaskCheckBox(8388608, "可以幻化")
            };

            return new BitmaskStackPanel("itemFlagsExtraSp", cbs);
        }

        public static BitmaskStackPanel GetClassFlags(int defaultValue)
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "战士"),
                new BitmaskCheckBox(2, "骑士"),
                new BitmaskCheckBox(4, "猎人"),
                new BitmaskCheckBox(8, "盗贼"),
                new BitmaskCheckBox(16, "牧师"),
                new BitmaskCheckBox(32, "死亡骑士"),
                new BitmaskCheckBox(64, "萨满"),
                new BitmaskCheckBox(128, "法师"),
                new BitmaskCheckBox(256, "术士"),
                new BitmaskCheckBox(512, "武僧(5.x)"),
                new BitmaskCheckBox(1024, "德鲁伊")
            };

            // default value must be -1!
            return new BitmaskStackPanel("classesSp", cbs, defaultValue);
        }

        public static BitmaskStackPanel GetRaceFlags(int defaultValue)
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "人类"),
                new BitmaskCheckBox(2, "兽人"),
                new BitmaskCheckBox(4, "矮人"),
                new BitmaskCheckBox(8, "暗夜精灵"),
                new BitmaskCheckBox(16, "被遗忘者"),
                new BitmaskCheckBox(32, "牛头人"),
                new BitmaskCheckBox(64, "侏儒"),
                new BitmaskCheckBox(128, "巨魔"),
                new BitmaskCheckBox(256, "地精(4.x)+"),
                new BitmaskCheckBox(512, "血精灵"),
                new BitmaskCheckBox(1024, "德莱尼"),
                new BitmaskCheckBox(2097152, "狼人(4.x)+"),
                new BitmaskCheckBox(58720256, "熊猫人(5.x)")
            };

            // default value must be -1!
            return new BitmaskStackPanel("racesSp", cbs, defaultValue);
        }

        public static BitmaskStackPanel GetBagFamilies()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Arrows"),
                new BitmaskCheckBox(2, "Bullets"),
                new BitmaskCheckBox(4, "Soul Shards"),
                new BitmaskCheckBox(8, "Leatherworking Supplies"),
                new BitmaskCheckBox(16, "Inscription Supplies"),
                new BitmaskCheckBox(32, "Herbs"),
                new BitmaskCheckBox(64, "Enchanting Supplies"),
                new BitmaskCheckBox(128, "Engineering Supplies"),
                new BitmaskCheckBox(256, "Keys"),
                new BitmaskCheckBox(512, "Gems"),
                new BitmaskCheckBox(1024, "Mining Supplies"),
                new BitmaskCheckBox(2048, "Soulbound Equipment"),
                new BitmaskCheckBox(4096, "Vanity Pets"),
                new BitmaskCheckBox(8192, "Currency Tokens"),
                new BitmaskCheckBox(16384, "Quest Items")
            };

            return new BitmaskStackPanel("bagFamilySp", cbs);
        }


        internal static BitmaskStackPanel GetNpcFlags()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Gossip"),
                new BitmaskCheckBox(2, "Questgiver"),
                new BitmaskCheckBox(16, "Trainer"),
                new BitmaskCheckBox(32, "Class Trainer"),
                new BitmaskCheckBox(64, "Profession Trainer"),
                new BitmaskCheckBox(128, "Vendor"),
                new BitmaskCheckBox(256, "Vendor Ammo"),
                new BitmaskCheckBox(512, "Vendor Food"),
                new BitmaskCheckBox(1024, "Vendor Poison"),
                new BitmaskCheckBox(2048, "Vendor Reagent"),
                new BitmaskCheckBox(4096, "Repairer"),
                new BitmaskCheckBox(8192, "Flight Master"),
                new BitmaskCheckBox(16384, "Only visible to dead players"),
                new BitmaskCheckBox(32768, "Spirit Guide"),
                new BitmaskCheckBox(65536, "Innkeeper"),
                new BitmaskCheckBox(131072, "Banker"),
                new BitmaskCheckBox(262144, "Petitioner"),
                new BitmaskCheckBox(524288, "Tabard Designer"),
                new BitmaskCheckBox(1048576, "Battlemaster"),
                new BitmaskCheckBox(2097152, "Auctioneer"),
                new BitmaskCheckBox(4194304, "Stable Master"),
                new BitmaskCheckBox(8388608, "Guild Banker"),
                new BitmaskCheckBox(16777216, "Spellclick (npc_spellclick_spells table)"),
                new BitmaskCheckBox(67108864, "Mailbox"),
            };
            return new BitmaskStackPanel("npcFlagsSp", cbs);
        }

        public static BitmaskStackPanel GetUnitFlags()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Server Controlled"),
                new BitmaskCheckBox(2 + 128, "Non Attackable"),
                new BitmaskCheckBox(8 + 4096, "PvP Attackable"),
                new BitmaskCheckBox(4, "Disable Move"),
                new BitmaskCheckBox(131072, "Pacified (Creature won't attack)"),
                new BitmaskCheckBox(262144, "Stunned"),
                new BitmaskCheckBox(4194304, "Confused"),
                new BitmaskCheckBox(8388608, "Fleeing"),
                new BitmaskCheckBox(16777216, "Player controlled (Vehicle, Eyes of the Beast, ...)"),
                new BitmaskCheckBox(33554432, "Not selectable"),
                new BitmaskCheckBox(67108864, "Skinnable"),
                new BitmaskCheckBox(134217728, "Is mount"),
                new BitmaskCheckBox(536870912, "Play dead"),
                new BitmaskCheckBox(1073741824, "Sheath weapon"),
            };
            return new BitmaskStackPanel("unitFlagsSp", cbs);
        }

        internal static BitmaskStackPanel GetInhabitTypes()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Ground", true),
                new BitmaskCheckBox(2, "Water", true),
                new BitmaskCheckBox(4, "Flying"),
            };
            return new BitmaskStackPanel("unitFlags2Sp", cbs);
        }

        public static BitmaskStackPanel GetUnitFlags2()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Feign Death"),
                new BitmaskCheckBox(2, "Hide (Only show equipment)"),
                new BitmaskCheckBox(4, "Ignore Reputation (friendly-faction combat)"),
                new BitmaskCheckBox(8, "Comprehend Language"),
                new BitmaskCheckBox(16, "Is mirror image"),
                new BitmaskCheckBox(64, "Force move"),
                new BitmaskCheckBox(128, "Disarm offhand"),
                new BitmaskCheckBox(16384, "Allow enemy interaction"),
                new BitmaskCheckBox(262144, "Allow cheat spells with AttributesEx7"),
            };
            return new BitmaskStackPanel("unitFlags2Sp", cbs);
        }

        public static BitmaskStackPanel GetCreatureDynamicFlags()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Lootable", true),
                new BitmaskCheckBox(2, "Track unit on minimap"),
                new BitmaskCheckBox(4, "Tapped (Grey name, Lua_UnitIsTapped)"),
                new BitmaskCheckBox(8, "Tapped by player"),
                new BitmaskCheckBox(32, "Is dead"),
                new BitmaskCheckBox(128, "Tapped by all thread list (Lua_UnitIsTappedByAllThreatList)"),
            };
            return new BitmaskStackPanel("dynamicFlagsSp", cbs);
        }

        public static BitmaskStackPanel GetCreatureTypeFlags()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Tamable"),
                new BitmaskCheckBox(2, "Ghost"),
                new BitmaskCheckBox(4, "Boss (Level ??)"),
                new BitmaskCheckBox(8, "No parry wound animation"),
                new BitmaskCheckBox(16, "Hide faction tooltip"),
                new BitmaskCheckBox(64, "Spell attackable", true),
                new BitmaskCheckBox(128, "Interact with players when NPC is dead"),
                new BitmaskCheckBox(256, "Herbable"),
                new BitmaskCheckBox(512, "Minable"),
                new BitmaskCheckBox(32768, "Engeneer loot"),
                new BitmaskCheckBox(1024, "Don't show death in combat log"),
                new BitmaskCheckBox(2048, "Mounted combat"),
                new BitmaskCheckBox(4096, "Aid players in combat"),
                new BitmaskCheckBox(8192, "Use pet bar"),
                new BitmaskCheckBox(65536, "Exotic tamable"),
                new BitmaskCheckBox(262144, "Siege weapon"),
                new BitmaskCheckBox(524288, "Takes siege damage"),
                new BitmaskCheckBox(1048576, "Hide nameplate"),
                new BitmaskCheckBox(2097152, "Do not play mounted animation"),
                new BitmaskCheckBox(8388608, "Only interact with it's creator"),
                new BitmaskCheckBox(134217728, "Force single gossip option"),
            };
            return new BitmaskStackPanel("creatureTypeFlagsSp", cbs);
        }

        internal static BitmaskStackPanel GetMechanicImmuneMask()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Charm"),
                new BitmaskCheckBox(2, "Disorient"),
                new BitmaskCheckBox(4, "Disarm"),
                new BitmaskCheckBox(8, "Distract"),
                new BitmaskCheckBox(16, "Fear"),
                new BitmaskCheckBox(32, "Grip"),
                new BitmaskCheckBox(64, "Root"),
                new BitmaskCheckBox(128, "Pacify"),
                new BitmaskCheckBox(256, "Silence"),
                new BitmaskCheckBox(512, "Sleep"),
                new BitmaskCheckBox(1024, "Snare"),
                new BitmaskCheckBox(2048, "Stun"),
                new BitmaskCheckBox(4096, "Freeze"),
                new BitmaskCheckBox(8192, "Knockout"),
                new BitmaskCheckBox(16384, "Bleed"),
                new BitmaskCheckBox(32768, "Bandage"),
                new BitmaskCheckBox(65536, "Polymorph"),
                new BitmaskCheckBox(131072, "Banish"),
                new BitmaskCheckBox(262144, "Shield"),
                new BitmaskCheckBox(524288, "Shackle (undead)"),
                new BitmaskCheckBox(1048576, "Mount"),
                new BitmaskCheckBox(2097152, "Infected"),
                new BitmaskCheckBox(4194304, "Turn Evil"),
                new BitmaskCheckBox(8388608, "Horror"),
                new BitmaskCheckBox(16777216, "Invulnerability (Forbearance, Nether Protection, Diplomatic Immunity only)"),
                new BitmaskCheckBox(33554432, "Interrupt"),
                new BitmaskCheckBox(67108864, "Daze"),
                new BitmaskCheckBox(134217728, "Discovery (create item effect)"),
                new BitmaskCheckBox(268435456, "Immune shield"),
                new BitmaskCheckBox(536870912, "Sapped"),
                new BitmaskCheckBox(1073741824, "Enraged"),
            };
            return new BitmaskStackPanel("mechanicImmuneMaskSp", cbs);
        }

        public static BitmaskStackPanel GetCreatureFlagsExtra()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Instance group bind"),
                new BitmaskCheckBox(2, "Civilian"),
                new BitmaskCheckBox(4, "No parry"),
                new BitmaskCheckBox(8, "No counter-attack at parry"),
                new BitmaskCheckBox(16, "No block"),
                new BitmaskCheckBox(32, "No crush attacks"),
                new BitmaskCheckBox(64, "No XP on kill"),
                new BitmaskCheckBox(128, "Is trigger NPC (invisible)"),
                new BitmaskCheckBox(256, "Immune to Taunt"),
                new BitmaskCheckBox(16384, "World event"),
                new BitmaskCheckBox(32768, "Guard"),
                new BitmaskCheckBox(131072, "No critical strikes"),
                new BitmaskCheckBox(262144, "No weapon skill gain"),
                new BitmaskCheckBox(524288, "Taunt diminish"),
                new BitmaskCheckBox(1048576, "All diminish"),
                new BitmaskCheckBox(2097152, "NPC's can help kill creature & player gets credit"),
                new BitmaskCheckBox(536870912, "Ignore pathfinding (like disabling mmaps for 1 creature)"),
                new BitmaskCheckBox(1073741824, "Immune to knockback"),
            };
            return new BitmaskStackPanel("creatureFlagsExtraSp", cbs);
        }
        public static BitmaskStackPanel GetCreatureBytes1()
        {
            var cbs = new List<BitmaskCheckBox>
            {
                new BitmaskCheckBox(1, "Always stand"),
                new BitmaskCheckBox(2, "Flying creature"),
                new BitmaskCheckBox(4, "Not trackable on minimap"),
                new BitmaskCheckBox(16, "Kneel"),
                new BitmaskCheckBox(48, "Lay down"),
            };
            return new BitmaskStackPanel("creatureBytes1Sp", cbs);
        }

        /// <summary>
        /// Returns true if checkbox with the specific bitmask value is checked
        /// </summary>
        /// <param name="v"></param>
        /// <returns></returns>
        internal bool HasValue(int v)
        {
            try
            {
                foreach (BitmaskCheckBox bmcb in Children)
                {
                    if ((long)bmcb.Tag == v) // Attempt to find bmcb with the requested value (defined in Tag)
                        return bmcb.IsChecked == true;
                }
                Logger.Log("BMSP: Failed to find BMCB with requested value in this BMSP.", Logger.Status.Warning, true);
                return false;
            }
            catch
            {
                Logger.Log("Error parsing data from BitmaskStackpanel. Output data may be invalid.", Logger.Status.Error, true);
                return false;
            }
        }
    }

    public class BitmaskCheckBox : CheckBox
    {
        public BitmaskCheckBox(long value, string details, bool isChecked = false,
            Visibility visibility = Visibility.Visible, string tooltip = "")
        {
            Tag = value;
            Content = details;
            IsChecked = isChecked;
            Visibility = visibility;
            ToolTip = tooltip;
        }

        public long GetValue()
        {
            return (long)Tag;
        }
    }
}